/**
 ******************************************************************************
 * @file	driver_opm.c
 * @brief	TR700-STM32 光源功率计驱动

- 2017-6-23,MenglongWu,MenglongWoo@aliyun.com
 *
 Copyright (C) 2017 桂林聚联科技有限公司, Inc. All Rights Reserved.
*/

#include <stdint.h>
#include <stdio.h>
#include <math.h>
#include "stm32f10x_dma.h"
#include "stm32f10x_adc.h"
#include "stm32f10x_dac.h"
#include "stm32f10x_tim.h"
#include "stm32f10x_flash.h"
#include "stm32f10x_spi.h"
#include "flash.h"
#include "stm32f10x.h"
#include "prj_type.h"
#include "usart.h"						//串口
#include "minishell-tiny.h"
#include "TR700Driver.h"
#include "project.h"



// ***************************************************************************
// 光功率计开关控制

#define RCC_OPM_SW     	RCC_APB2Periph_GPIOE
#define GROUP_OPM_SW   	GPIOE
#define OPM_SW_E1 		GPIO_Pin_2
#define OPM_SW_E2 		GPIO_Pin_3
#define OPM_SW_E3 		GPIO_Pin_4
#define OPM_SW_E4 		GPIO_Pin_5
#define PIN_OPM_SW     	( OPM_SW_E1 |  OPM_SW_E2 | OPM_SW_E3 | OPM_SW_E4)


void Init_OPM_SW()
{
	GPIO_InitTypeDef GPIO_InitStructure;


	// 脉冲激光器 LED
	RCC_APB2PeriphClockCmd(RCC_OPM_SW, ENABLE);
	GPIO_InitStructure.GPIO_Speed	= GPIO_Speed_2MHz;
	GPIO_InitStructure.GPIO_Pin	= PIN_OPM_SW;
	GPIO_InitStructure.GPIO_Mode	= GPIO_Mode_Out_PP;
	GPIO_Init(GROUP_OPM_SW, &GPIO_InitStructure);
}










#define RESET_ALL (OPM_SW_E1 | OPM_SW_E2 | OPM_SW_E3 | OPM_SW_E4)

#define SET_LV_UNUSE  (0)
// 1档 E1 E2 E3 E4 = 0 0 0 0
#define SET_LV1  (0)
// 2档 E1 E2 E3 E4 = 1 0 0 0
#define SET_LV2  (OPM_SW_E1)
// 3档 E1 E2 E3 E4 = 0 1 0 0
#define SET_LV3  (OPM_SW_E2)
// 4档 E1 E2 E3 E4 = 1 1 0 0
#define SET_LV4  (OPM_SW_E1 | OPM_SW_E2)
// 5档 E1 E2 E3 E4 = 1 1 1 0
#define SET_LV5  (OPM_SW_E1 | OPM_SW_E2 | OPM_SW_E3)
// 6档 E1 E2 E3 E4 = 1 1 0 1
#define SET_LV6  (OPM_SW_E1 | OPM_SW_E2 | OPM_SW_E4)
// 7档 E1 E2 E3 E4 = 1 1 1 1
#define SET_LV7  (OPM_SW_E1 | OPM_SW_E2 | OPM_SW_E3 | OPM_SW_E4)


static int _s_cur_opm_sw = 1;
void Ctrl_OPM_SW(int index)
{
	uint16_t levels[] = {
		SET_LV_UNUSE,
		SET_LV1,
		SET_LV2,
		SET_LV3,
		SET_LV4,
		SET_LV5,
		SET_LV6,
		SET_LV7,
#ifdef DBG_OPM_SW
		SET_LV_UNUSE,
		SET_LV_UNUSE,
		SET_LV_UNUSE,
		OPM_SW_E1,
		OPM_SW_E2,
		OPM_SW_E3,
		OPM_SW_E4,
#endif
	};
	uint16_t io;
	if ((unsigned int)index >= ARRAY_SIZE(levels)) {
		return ;
	}
	io = levels[index];
	_s_cur_opm_sw = index;
	// TODO 暂停ADC
	GPIO_ResetBits(GROUP_OPM_SW, RESET_ALL);
	GPIO_SetBits(GROUP_OPM_SW, io);
	// TODO 等待若干ms，冲掉不稳定的ADC数据
	// TODO 启动ADC
}
int Get_OPM_SW()
{
	return _s_cur_opm_sw;
}


int Ctrl_OPMWave(int index)
{
	switch(index) {
	case CTRL_OPM_WAVE_1310:
		dev_opm.k_ref_1310 = 1;
		break;
	case CTRL_OPM_WAVE_1550:
		dev_opm.k_ref_1310 = sys_param._1550_ref_1310;
		break;
	case CTRL_OPM_WAVE_1490:
		dev_opm.k_ref_1310 = sys_param._1490_ref_1310;
		break;
	case CTRL_OPM_WAVE_1625:
		dev_opm.k_ref_1310 = sys_param._1625_ref_1310;
		break;
	case CTRL_OPM_WAVE_850:
		dev_opm.k_ref_1310 = sys_param._850_ref_1310;
		break;
	default:
		return -1;
	}
	return 0;
}

//***************************************************************
// 稳态控制
/*
   -.--.----.------------.------------.-----.----.-->
    0  l'   l            m            h     h'  4095
           Bl                         Bh
*/

struct overflow_limit {
	unsigned short over_low_l;   // l'
	unsigned short over_low;     // l
	unsigned short over_high;    // h
	unsigned short over_high_l;  // h'  暂时无用
	unsigned long  min;          // m
	long base_low;               // Bl  l位置表示多少dbm
	long base_high;              // Bh  h位置表示多少dbm
};

static struct overflow_limit g_ol[7];
struct overflow_limit *pg_ol = &g_ol[0];

int Init_Overflow(struct adj_power_flash *p)
{
	g_ol[0].over_low = (unsigned short)p->lv1_low;
	g_ol[1].over_low = (unsigned short)p->lv2_low;
	g_ol[2].over_low = (unsigned short)p->lv3_low;
	g_ol[3].over_low = (unsigned short)p->lv4_low;
	g_ol[4].over_low = (unsigned short)p->lv5_low;
	g_ol[5].over_low = (unsigned short)p->lv6_low;
	g_ol[6].over_low = (unsigned short)p->lv7_low;

	g_ol[0].over_low_l = (unsigned short)(LOW_PRESENT * g_ol[0].over_low);
	g_ol[1].over_low_l = (unsigned short)(LOW_PRESENT * g_ol[1].over_low);
	g_ol[2].over_low_l = (unsigned short)(LOW_PRESENT * g_ol[2].over_low);
	g_ol[3].over_low_l = (unsigned short)(LOW_PRESENT * g_ol[3].over_low);
	g_ol[4].over_low_l = (unsigned short)(LOW_PRESENT * g_ol[4].over_low);
	g_ol[5].over_low_l = (unsigned short)(LOW_PRESENT * g_ol[5].over_low);
	g_ol[6].over_low_l = (unsigned short)(LOW_PRESENT * g_ol[6].over_low);

	g_ol[0].over_high = (unsigned short)p->lv1_high;
	g_ol[1].over_high = (unsigned short)p->lv2_high;
	g_ol[2].over_high = (unsigned short)p->lv3_high;
	g_ol[3].over_high = (unsigned short)p->lv4_high;
	g_ol[4].over_high = (unsigned short)p->lv5_high;
	g_ol[5].over_high = (unsigned short)p->lv6_high;
	g_ol[6].over_high = (unsigned short)p->lv7_high;


	g_ol[0].min = (g_ol[0].over_high + g_ol[0].over_low) / 2;
	g_ol[1].min = (g_ol[1].over_high + g_ol[1].over_low) / 2;
	g_ol[2].min = (g_ol[2].over_high + g_ol[2].over_low) / 2;
	g_ol[3].min = (g_ol[3].over_high + g_ol[3].over_low) / 2;
	g_ol[4].min = (g_ol[4].over_high + g_ol[4].over_low) / 2;
	g_ol[5].min = (g_ol[5].over_high + g_ol[5].over_low) / 2;
	g_ol[6].min = (g_ol[6].over_high + g_ol[6].over_low) / 2;

	g_ol[0].base_low =  -0 - OPT_OFFSET;
	g_ol[1].base_low = -10 - OPT_OFFSET;
	g_ol[2].base_low = -20 - OPT_OFFSET;
	g_ol[3].base_low = -30 - OPT_OFFSET;
	g_ol[4].base_low = -40 - OPT_OFFSET;
	g_ol[5].base_low = -50 - OPT_OFFSET;
	g_ol[6].base_low = -60 - OPT_OFFSET;

	g_ol[0].base_high =  10 - OPT_OFFSET;
	g_ol[1].base_high =  -0 - OPT_OFFSET;
	g_ol[2].base_high = -10 - OPT_OFFSET;
	g_ol[3].base_high = -20 - OPT_OFFSET;
	g_ol[4].base_high = -30 - OPT_OFFSET;
	g_ol[5].base_high = -40 - OPT_OFFSET;
	g_ol[6].base_high = -50 - OPT_OFFSET;

	printf("low %4d min %4d high %4d\r\nBl %d Bh %d\r\n",
	       g_ol[2].over_low, g_ol[2].min, g_ol[2].over_high,
	       g_ol[2].base_low, g_ol[2].base_high);
}
int OnOverflow_High()
{
	int next_lv = Get_OPM_SW() - 1;

	Ctrl_OPM_SW(next_lv);
	if (pg_ol - g_ol > 0) {
		pg_ol--;
	}
}

int OnOverflow_Low()
{
	int next_lv = Get_OPM_SW() + 1;

	Ctrl_OPM_SW(next_lv);
	if (pg_ol < g_ol + ARRAY_SIZE(g_ol) - 1) {
		pg_ol++;
	}
}


float Calc_ADC2dBm(int fun_select, unsigned short adc)
{
	unsigned short div;
	long base;
	float y;
	float k = dev_opm.k_ref_1310;  // 1310nm 参考值

	pg_ol = g_ol + Get_OPM_SW() - 1;

	switch(fun_select) {
	case F_ADC2DBM_LOW:
		div  = pg_ol->over_low;
		base = pg_ol->base_low;
		break;
	case F_ADC2DBM_HIGH:
		div  = pg_ol->over_high;
		base = pg_ol->base_high;
		break;
	}

#if 0  // TODO 根据波长选择系数
	GetWave();
#else

#endif
	y = 10 * log10((float)adc / div) + base;
	y = y * k;
	return y;
}

float AutoADC2dBm()
{
	unsigned short adc;

	adc = GetAD(AD_CH_OPM);
	if (adc > pg_ol->min) {
		return Calc_ADC2dBm(F_ADC2DBM_HIGH, adc);
	} else {
		return Calc_ADC2dBm(F_ADC2DBM_LOW, adc);
	}
}
void AutoCtrl_OPM()
{
	unsigned short adc;

	adc = GetAD(AD_CH_OPM);

#if 0
	printf("\r\n%x %x date %d low_l %4d min %4d mid %4d max %4d  adc %4d\r\n",
	       pg_ol, g_ol, (pg_ol - g_ol) / sizeof(struct overflow_limit),
	       pg_ol->over_low_l, pg_ol->over_low, pg_ol->min, pg_ol->over_high,
	       adc);
#endif
	if (adc > pg_ol->min) {
		Calc_ADC2dBm(F_ADC2DBM_HIGH, adc);
	} else {
		Calc_ADC2dBm(F_ADC2DBM_LOW, adc);
	}
	if (adc >= pg_ol->over_high) {
#if 0
		printf("Onhigh\r\n");
#endif
		OnOverflow_High();
	} else if (adc <= pg_ol->over_low_l) {
#if 0
		printf("Onlow\r\n");
#endif
		OnOverflow_Low();
	}
}